#ifndef __LYNX_LISTENER_HPP_INCLUDED__
#define __LYNX_LISTENER_HPP_INCLUDED__

#include <MythMath.hpp>

namespace Lynx
{
namespace Audio
{

enum LYNX_AUDIO_DISTANCE_MODEL
{
    LADM_NONE,
    LADM_INVERSE,
    LADM_INVERSE_CLAMPED,
    LADM_LINEAR,
    LADM_LINEAR_CLAMPED,
    LADM_EXPONENT,
    LADM_EXPONENT_CLAMPED
};

class Listener
{
public:
    ////////////////////////////////////////////////////////////////////////////
    //! \brief Sets the position of the listener.
    /*!
     * \param[in] position The position you want the listener to have.
     *
     * \throw Exception If the manager is not active, it will throw an invalid
     *                  state exception.
     */
    virtual void set_position(const Myth::Math::Vector3f &position) = 0;


    ////////////////////////////////////////////////////////////////////////////
    //! \brief Returns the current position of the listener.
    /*!
     * \return The current position of the listener.
     *
     * \throw Exception If the manager is not active, it will throw an invalid
     *                  state exception.
     */
    virtual Myth::Math::Vector3f get_position(void) const = 0;


    ////////////////////////////////////////////////////////////////////////////
    //! \brief Sets the velocity vector of the listener.
    /*!
     * \param[in] velocity The velocity you want the listener to have.
     *
     * \throw Exception If the manager is not active, it will throw an invalid
     *                  state exception.
     */
    virtual void set_velocity(const Myth::Math::Vector3f &velocity) = 0;


    ////////////////////////////////////////////////////////////////////////////
    //! \brief Returns the current velocity of the listener.
    /*!
     * \return The current velocity of the listener.
     *
     * \throw Exception If the manager is not active, it will throw an invalid
     *                  state exception.
     */
    virtual Myth::Math::Vector3f get_velocity(void) const = 0;


    ////////////////////////////////////////////////////////////////////////////
    //! \brief Sets the up vector of the listener.
    /*!
     * \param[in] up The up vector you want the listener to have.
     *
     * \throw Exception If the manager is not active, it will throw an invalid
     *                  state exception.
     */
    virtual void set_up_vector(const Myth::Math::Vector3f &up) = 0;


    ////////////////////////////////////////////////////////////////////////////
    //! \brief Returns the current up vector of the listener.
    /*!
     * \return The current up vector of the listener.
     *
     * \throw Exception If the manager is not active, it will throw an invalid
     *                  state exception.
     */
    virtual Myth::Math::Vector3f get_up_vector(void) const = 0;


    ////////////////////////////////////////////////////////////////////////////
    //! \brief Sets the target of the listener.
    /*!
     * \param[in] target The target you want the listener to have.
     *
     * \throw Exception If the manager is not active, it will throw an invalid
     *                  state exception.
     */
    virtual void set_target(const Myth::Math::Vector3f &target) = 0;


    ////////////////////////////////////////////////////////////////////////////
    //! \brief Returns the current target of the listener.
    /*!
     * \return The current target of the listener.
     *
     * \throw Exception If the manager is not active, it will throw an invalid
     *                  state exception.
     */
    virtual Myth::Math::Vector3f get_target(void) const = 0;


    ////////////////////////////////////////////////////////////////////////////
    //! \brief Sets the target as well as the up vector of the listener.
    /*!
     * \param[in] target The target you want the listener to have.
     *
     * \param[in] up The up vector you want the listener to have.
     *
     * \throw Exception If the manager is not active, it will throw an invalid
     *                  state exception.
     */
    virtual void set_orientation(const Myth::Math::Vector3f &target,
                                 const Myth::Math::Vector3f &up) = 0;


    ////////////////////////////////////////////////////////////////////////////
    //! \brief Sets the volume.
    /*!
     * \param[in] volume The volume in the range [0, 1]. Values larger than 1
     *                   may be accepted by some soundcards and will 'boost' the
     *                   sound.
     *
     * \throw Exception If the manager is not active, it will throw an invalid
     *                  state exception.
     */
    virtual void set_volume(float volume = 1.0f) = 0;


    ////////////////////////////////////////////////////////////////////////////
    //! \brief Returns the current volume.
    /*!
     * \return The current volume.
     *
     * \throw Exception If the manager is not active, it will throw an invalid
     *                  state exception.
     */
    virtual float get_volume(void) const = 0;


    ////////////////////////////////////////////////////////////////////////////
    //! \brief Sets the doppler factor.
    /*!
     * \param[in] factor The doppler factor. Must be positive and zero disables
     *                   the effect.
     */
    virtual void set_doppler_factor(float factor = 1.0) = 0;


    ////////////////////////////////////////////////////////////////////////////
    //! \brief Returns the doppler factor.
    /*!
     * \return The doppler factor.
     */
    virtual float get_doppler_factor(void) const = 0;


    ////////////////////////////////////////////////////////////////////////////
    //! \brief Sets the speed of sound. Used in doppler calculations.
    /*!
     * \param[in] speed The speed of sound. Must be larger than zero.
     */
    virtual void set_speed_of_sound(float speed = 343.3f) = 0;


    ////////////////////////////////////////////////////////////////////////////
    virtual float get_speed_of_sound(void) const = 0;


    ////////////////////////////////////////////////////////////////////////////
    virtual void set_distance_model(LYNX_AUDIO_DISTANCE_MODEL model) = 0;


    ////////////////////////////////////////////////////////////////////////////
    virtual LYNX_AUDIO_DISTANCE_MODEL get_distance_model(void) const = 0;
};

} // namespace Audio
} // namespace Lynx

#endif // __LYNX_LISTENER_HPP_INCLUDED__


